#include <stdio.h>

#define NOP   0x0000          /* ＮＯＰコマンド */
#define TERM  0xbeef          /* 終端コマンド */
#define VERSION   "0.02a"     /* バージョン */

short xmin,xmax;              /* 最小・最大値 */
short ymin,ymax;              /* 最小・最大値 */
short zmin,zmax;              /* 最小・最大値 */
unsigned char arrname[256];   /* 配列名格納バッファ */
unsigned long length,i;       /* レングス・ループカウンタ */
unsigned long FileP;          /* ファイルループカウンタ */
unsigned long tindex[512];    /* テクスチャーインデックス */
unsigned long ntextures;      /* テクスチャーコマンドの数 */
unsigned short temp;          /* テンポラリ */
unsigned short paclen;        /* パケット長 */
unsigned short paccom;        /* コマンド */

/* -------------------------------------------------------- */
/* 最小値・最大値の比較 */
void
minmax(short x, short y, short z)
{
  if (xmin > x) xmin = x;
  if (xmax < x) xmax = x;
  if (ymin > y) ymin = y;
  if (ymax < y) ymax = y;
  if (zmin > z) zmin = z;
  if (zmax < z) zmax = z;
}
/* -------------------------------------------------------- */
void
main(int argc, char *argv[])
{
  FILE *fp;
  short combuf[256];
/* -------------------------------------------------------- */
  fprintf(stderr,
        "make min,max,tindex and ntextures data from agc ver."VERSION"\n");
/* 引き数がなかった場合の処理 */
  if (argc < 2){
    fprintf(stderr,"Usage:agc2mm <agcfile> [<arrangement name>]\n");
    exit(1);
  }
/* 配列名初期化 */
  arrname[0] = '\0';
/* 配列名が指定されていたら取り込む */
  if (argc > 2){
    sprintf(arrname,"%s_",argv[2]);
  }
/* ファイルを開いて見る */
  if ((fp = fopen(argv[1],"rb")) == NULL){
    fprintf(stderr,"File not found.\n");
    exit(1);
  }
/* ＡＧＣのレングスを読む */
  if (fread(&length,sizeof(unsigned long),1,fp) == 0){
    fprintf(stderr,"File broken.\n");
    exit(1);
  }
/* -------------------------------------------------------- */
/* 最小値に最大・最大値に最小の値をいれておく */
  xmin = 0x7fff;
  ymin = 0x7fff;
  zmin = 0x7fff;
  xmax = 0x8000;
  ymax = 0x8000;
  zmax = 0x8000;
  ntextures = 0;
/* -------------------------------------------------------- */
  /* レングス分のループ */
  for(FileP = 0; FileP < length;){
    /* 最初の１ワードを読む */
    if (fread(&temp,sizeof(unsigned short),1,fp) == 0){
      fprintf(stderr,"command broken.\n");
      exit(1);
    }
    FileP += sizeof(unsigned short);

    /* ＮＯＰでも終端でもなかったらコマンド */
    if(temp != NOP && temp != TERM){
      /* コマンドを発見 */
      paccom = (temp & 0xff00) >> 8;    /* コマンド部分の抽出 */
      paclen = (unsigned char)temp;     /* パケット長の抽出 */
      /* パケット長−１だけ読む */
      if (fread(combuf,sizeof(short),paclen - 1,fp) < (paclen - 1)){
        fprintf(stderr,"command length broken.\n");
        exit(1);
      }
      /* 読み込んだ分を足す */
      FileP += (paclen - 1) * sizeof(short);
      /* コマンド毎の処理 */
      switch(paccom){
        case 0x10:
          for ( i = 0; i < paclen - 1; i += 4){
            minmax (combuf[i + 1], combuf[i + 2], combuf[i + 3]);
          }
          break;
        case 0x11:
          for ( i = 0; i < paclen - 1; i += 7){
            minmax (combuf[i + 1], combuf[i + 2], combuf[i + 3]);
          }
          break;
        case 0x12:
          for ( i = 0; i < 7; i+= 3){
            minmax (combuf[i + 0], combuf[i + 1], combuf[i + 2]);
          }
          for ( i = 7; i < paclen - 1; i += 7){
            minmax (combuf[i + 0], combuf[i + 1], combuf[i + 2]);
          }
          break;
        case 0x14:
          for ( i = 0; i < paclen - 1; i += 5){
            minmax (combuf[i + 2], combuf[i + 3], combuf[i + 4]);
          }
          break;
        case 0x15:
          for ( i = 0; i < paclen - 1; i += 8){
            minmax (combuf[i + 2], combuf[i + 3], combuf[i + 4]);
          }
          break;
        case 0x16:
          for ( i = 0; i < 10; i+= 5){
            minmax (combuf[i + 2], combuf[i + 3], combuf[i + 4]);
          }
          for ( i = 10; i < paclen - 1; i += 8){
            minmax (combuf[i + 2], combuf[i + 3], combuf[i + 4]);
          }
          break;
        case 0x18:
          for ( i = 0; i < paclen - 1; i += 3){
            minmax (combuf[i + 0], combuf[i + 1], combuf[i + 2]);
          }
          break;
        case 0x19:
          for ( i = 0; i < paclen - 1; i += 6){
            minmax (combuf[i + 0], combuf[i + 1], combuf[i + 2]);
          }
          break;
        case 0x1a:
          for ( i = 0; i < 6; i+= 3){
            minmax (combuf[i + 0], combuf[i + 1], combuf[i + 2]);
          }
          for ( i = 6; i < paclen - 1; i += 6){
            minmax (combuf[i + 0], combuf[i + 1], combuf[i + 2]);
          }
          break;
        case 0x20:
          for ( i = 0; i < paclen - 1; i += 4){
            minmax (combuf[i + 1], combuf[i + 2], combuf[i + 3]);
          }
          break;
        case 0x21:
          for ( i = 0; i < paclen - 1; i += 7){
            minmax (combuf[i + 1], combuf[i + 2], combuf[i + 3]);
          }
          break;
        case 0x22:
          for ( i = 0; i < paclen - 1; i += 13){
            minmax (combuf[i + 0], combuf[i + 1], combuf[i + 2]);
            minmax (combuf[i + 3], combuf[i + 4], combuf[i + 5]);
            minmax (combuf[i + 7], combuf[i + 8], combuf[i + 9]);
          }
          break;
        case 0x24:
          for ( i = 0; i < paclen - 1; i += 5){
            minmax (combuf[i + 2], combuf[i + 3], combuf[i + 4]);
          }
          break;
        case 0x25:
          for ( i = 0; i < paclen - 1; i += 8){
            minmax (combuf[i + 2], combuf[i + 3], combuf[i + 4]);
          }
          break;
        case 0x26:
          for ( i = 0; i < paclen - 1; i += 18){
            minmax (combuf[i + 2], combuf[i + 3], combuf[i + 4]);
            minmax (combuf[i + 7], combuf[i + 8], combuf[i + 9]);
            minmax (combuf[i +12], combuf[i +13], combuf[i +14]);
          }
          break;
        case 0x28:
          for ( i = 0; i < paclen - 1; i += 3){
            minmax (combuf[i + 0], combuf[i + 1], combuf[i + 2]);
          }
          break;
        case 0x29:
          for ( i = 0; i < paclen - 1; i += 6){
            minmax (combuf[i + 0], combuf[i + 1], combuf[i + 2]);
          }
          break;
        case 0x2a:
          for ( i = 0; i < paclen - 1; i += 12){
            minmax (combuf[i + 0], combuf[i + 1], combuf[i + 2]);
            minmax (combuf[i + 3], combuf[i + 4], combuf[i + 5]);
            minmax (combuf[i + 6], combuf[i + 7], combuf[i + 8]);
          }
          break;
        case 0x90:
          /* texture select register */
          tindex[ntextures] = FileP - sizeof(unsigned short) * 2;
          ntextures ++;
          break;
        default:
          /* サポートしてないコマンドだった場合の処理 */
          fprintf(stderr,"Unsupport packet : %04x length: %04x",paccom,paclen);
          switch(paccom >> 4){
            case 3:
              fprintf(stderr," Poly line.\n");
              break;
            case 4:
              fprintf(stderr," Line list.\n");
              break;
            case 5:
              fprintf(stderr," Reserved.\n");
              break;
            case 6:
              fprintf(stderr," Put image.\n");
              break;
            case 7:
              fprintf(stderr," Read pixel.\n");
              break;
            case 8:
              fprintf(stderr," Write TE registers.\n");
              break;
            case 9:
              fprintf(stderr," Write PE registers.\n");
              break;
            case 10:
              fprintf(stderr," Misc command.\n");
              break;
            case 11:
              fprintf(stderr," Reserved.\n");
              break;
            case 12:
              fprintf(stderr," Read TE registers.\n");
              break;
            case 13:
              fprintf(stderr," Read PE registers.\n");
              break;
            case 14:
              fprintf(stderr," Write LUT.\n");
              break;
            case 15:
              fprintf(stderr," Read LUT.\n");
              break;
            default:
              fprintf(stderr,"\n");
              break;
          }
          break;
      }
      /* コマンド毎の処理終わり */
    }
    /* コマンド終わり */
  }
  /* ファイルを閉じる */
  fclose(fp);
  /* 標準出力に結果を出力する */
  printf("/* Xmin, Ymin, Zmin, Xmax, Ymax, Zmax */\nunsigned short %sminmax[] = {",arrname);
  printf(" 0x%04x,0x%04x,0x%04x,",xmin,ymin,zmin);
  printf("0x%04x,0x%04x,0x%04x, };\n",xmax,ymax,zmax);
  printf("\nint %stindex[] = {",arrname);
  for (i = 0; i < ntextures; i++){
    if ((i & 0x07) == 0){
      printf("\n");
    }
    printf("%d,",tindex[i] / sizeof(int));
  }
  if (ntextures == 0)
    printf("\n");
  printf("-1\n};\n\nint %sntextures = %d ;\n",arrname,ntextures);
}
